/* ************************************************************************* **
**    OpenVFIFE - Open System for Vector Form Instrinsic                     **
**                Finite Element Method (VFIFE)                              **
**                GinkGo(Tan Biao)                                           **
**                                                                           **
**                                                                           **
** (C) Copyright 2021, The GinkGo(Tan Biao). All Rights Reserved.            **
**                                                                           **
** Commercial use of this program without express permission of              **
** GinkGo(Tan Biao), is strictly prohibited.  See                            **
** file 'COPYRIGHT'  in main directory for information on usage and          **
** redistribution,  and for a DISCLAIMER OF ALL WARRANTIES.                  **
**                                                                           **
** Developed by:                                                             **
**      Tan Biao (ginkgoltd@outlook.com)                                     **
**                                                                           **
** ************************************************************************* */

// $Date: 2020-05-11 $
// Written: Tan Biao
// Revised:
//
// Purpose: This file contains the class definition for StructSystem

// The interface:
//

#ifndef STRUCTSYSTEM_H_
#define STRUCTSYSTEM_H_
#include <unistd.h>
#include <sys/stat.h>
#include <errno.h>
#include "particle.h"
#include "material.h"
#include "section.h"
#include "element.h"


class StructSystem
{
    private:
        double h_;
        double alpha_; // mass damping coefficient
        double beta_; // stiffness damping coefficient, default to be 0,

    protected:
        int id_;
        double critical_time_step_;
        std::string workdir_;
        std::string jobname_;
        std::map <int, Particle*> particles_;
        std::map <int, BaseMaterial*> materials_;
        std::map <int, BaseSection*> sections_;
        std::map <int, BaseElement*> elements_;
        std::vector <std::string> elem_types_;
        int elem_max_nodes_;
        std::map <int, DOF> constraints_;
        void constraint();

    public:
        StructSystem(int id);
        ~StructSystem();
        std::string jobname() const;
        std::string workdir() const;
        double critical_time_step() const;
        double timestep() const;

        const std::map<int, Particle*>* particles() const;
        const std::map<int, BaseMaterial*>* materials() const;
        const std::map<int, BaseSection*>* sections() const;
        const std::map<int, BaseElement*>* elements() const;
        const std::map<int, DOF>* constraints() const;
        void info() const;

        void setWorkdir(const std::string &dir);
        void setJobname(const std::string &job);
        double autoTimeStep();
        void setTimeStep(double h);
        void setDampCoeff(double alpha, double beta=0.0);

        void addParticle(Particle* p);
        void addParticles(const std::vector <Particle *> &ps);
        void addParticles(const std::map<int, Particle*> &ps);

        void addElement(BaseElement* e);
        void addElements(const std::vector <BaseElement *> &elems);
        void addElements(const std::map<int, BaseElement*> &elems);

        void addMaterial(BaseMaterial* mat);
        void addMaterials(const std::vector <BaseMaterial*> &mats);
        void addMaterials(const std::map<int, BaseMaterial*> &mats);

        void addSection(BaseSection* sect);
        void addSections(const std::vector <BaseSection*> &sects);
        void addSections(const std::map<int, BaseSection*> &sects);

        void addConstraint(int pid, const DOF &dof);
        int deleteConstraint(int pid);
        void changeConstraint(int pid, const DOF &dof);
        void clearConstraint();

        void setParticleDisplace(int pid, const StdArray6d &val);
        void addParticleDisplace(int pid, const StdArray6d &val);
        void setAccelerate(double ax, double ay, double az);
        void setExternalForce(int pid, const StdArray6d &val);
        void addExternalForce(int pid, const StdArray6d &val);
        void setInternalForce();
        void clearParticleForce();

        void solve(double h, double zeta=0.2, bool firstStep=false);
        void solve(bool firstStep=false);
        void saveModel(const std::string &path);
        void saveParticleResult(const std::string &path);
        void saveElementResult(const std::string &path);
        void saveSupportReact(const std::string &path);
        void saveResult(const std::string &path);

        // do it when you add new object into particles_, elements_
        void releaseContainers();

    // methods for collapse analysis
    protected:
        std::map<int, BaseElement*> failure_elems_;
        std::map<int, int> particle_connected_elems_;
        std::map<int, Particle*> free_particles_;

    public:
        void killElement(const int id);
        void autoKillElement();
        void removeFreeParticle();
        void countParticleConnectedElements(); // will be removed in future

};


// other functions
bool isFileExists(const std::string &fname);
bool isDirExists(const std::string &path);
bool makedir(const std::string &path);
double interpolate(std::vector<double> &xData, std::vector<double> &yData,
    double x, bool extrapolate);

#endif